import unittest

from log_parser import LogParser, ParsingException

new_session_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\"}"},
{"timestamp":30,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\"}"}]"""

two_command_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"firstCommand\\"}"},
{"timestamp":30,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"firstCommand\\"}"},
{"timestamp":40,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":50,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"secondCommand\\"}"}]"""

nested_event_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"firstCommand\\"}"},
{"timestamp":15,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"start\\"}"},
{"timestamp":25,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"end\\"}"},
{"timestamp":30,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"firstCommand\\"}"}]"""

differently_nested_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"firstCommand\\"}"},
{"timestamp":20,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"firstCommand\\"}"},
{"timestamp":25,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":26,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":27,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":28,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":29,"message":"{\\"event\\":\\"SUB_SUB_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":90,"message":"{\\"event\\":\\"SUB_SUB_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":100,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":110,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":120,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":130,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"secondCommand\\"}"},
{"timestamp":150,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"thirdCommand\\"}"},
{"timestamp":160,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"thirdCommand\\"}"},
{"timestamp":170,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"thirdCommand\\"}"},
{"timestamp":180,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"thirdCommand\\"}"},
{"timestamp":190,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"thirdCommand\\"}"},
{"timestamp":200,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"thirdCommand\\"}"}]"""

missing_end_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\"}"}]"""

missing_start_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\"}"}]"""

missing_second_start_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\"}"},
{"timestamp":20,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\"}"},
{"timestamp":30,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\"}"}]"""

wrong_order_same_timestamp_log = """[{"timestamp":10,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"start\\",\\"command\\":\\"firstCommand\\"}"},
{"timestamp":15,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"start\\"}"},
{"timestamp":30,"message":"{\\"event\\":\\"HTTP_COMMAND\\",\\"startorend\\":\\"end\\",\\"command\\":\\"firstCommand\\"}"},
{"timestamp":30,"message":"{\\"event\\":\\"SUB_COMMAND\\",\\"startorend\\":\\"end\\"}"}]"""

class LogParserTest(unittest.TestCase):
    def testFillsInEndTime(self):
        log = self.ParseString(new_session_log)
        self.assertEquals(len(log), 1)
        entry = log[0]
        self.assertEquals(entry['end'] - entry['start'], 20)

    def testHandlesMultipleCommands(self):
        log = self.ParseString(two_command_log)
        self.assertEquals(len(log), 2)
        self.assertEquals(log[0]['command'], 'firstCommand')
        self.assertEquals(log[1]['command'], 'secondCommand')

    def testDealsWithWrongOrderSameTimestamps(self):
        log = self.ParseString(wrong_order_same_timestamp_log)
        self.assertEquals(len(log), 1)
        self.assertEquals(log[0]['event'], 'HTTP_COMMAND')
        self.assertEquals(len(log[0]['children']), 1)
        self.assertEquals(log[0]['children'][0]['event'], 'SUB_COMMAND')

    def testDealsWithNestedEvents(self):
        log = self.ParseString(nested_event_log)
        self.assertEquals(len(log), 1)
        self.assertEquals(log[0]['event'], 'HTTP_COMMAND')
        self.assertEquals(len(log[0]['children']), 1)
        self.assertEquals(log[0]['children'][0]['event'], 'SUB_COMMAND')

    def testDealsWithDifferentLevelsOfNesting(self):
        log = self.ParseString(differently_nested_log)
        self.assertEqual(len(log), 3)
        self.assertEquals(len(log[0]['children']), 0)
        self.assertEquals(len(log[1]['children']), 3)
        self.assertEquals(len(log[1]['children'][0]['children']), 0)
        self.assertEquals(len(log[1]['children'][1]['children']), 1)
        self.assertEquals(len(log[1]['children'][1]['children'][0]['children']), 0)
        self.assertEquals(len(log[1]['children'][2]['children']), 0)
        self.assertEquals(len(log[2]['children']), 2)
        self.assertEquals(len(log[2]['children'][0]['children']), 0)
        self.assertEquals(len(log[2]['children'][1]['children']), 0)

    def testMissingEndLogThrows(self):
        try:
            LogParser().ParseString(missing_end_log)
            self.fail('Expected exception')
        except ParsingException as e:
            self.assertTrue('Missing end of started command' in str(e))

    def testMissingFirstStartLogThrows(self):
        try:
            LogParser().ParseString(missing_start_log)
            self.fail('Expected exception')
        except ParsingException as e:
            self.assertTrue(
                'First command was not the start of a command' in str(e))

    def testMissingStartLogThrows(self):
        try:
            LogParser().ParseString(missing_second_start_log)
            self.fail('Expected exception')
        except ParsingException as e:
            self.assertTrue('Missing start of ended command' in str(e))

    def testCompensatesForStartTime(self):
        log = self.ParseString(two_command_log)
        self.assertEquals(log[0]['start'], 0)
        self.assertEquals(log[0]['end'], 20)
        self.assertEquals(log[1]['start'], 30)
        self.assertEquals(log[1]['end'], 40)

    def ParseString(self, string):
        self.log = LogParser().ParseString(string)
        return self.log

if __name__ == '__main__':
    unittest.main()
